package cc.zstart.generator.mybatis.util;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.TransformerConfigurationException;

import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.exception.XMLParserException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @desc <p>
 * </p>
 * @author DaiJiangGuo
 * @date 2015年5月15日下午7:12:26
 */
public class XmlMapperUtil {
    public static String indent = "  ";
    public static String newLine = "\n";

    /**
     * @author DaiJiangGuo
     * @data 2015年5月15日 下午7:13:49
     * @param addIntroCols
     * @param targetFile
     * @param sqlMap
     * @param introspectedTable
     * @throws XMLParserException
     * @throws IOException
     * @throws TransformerConfigurationException
     */
    public static void mergedAddColSource(List<IntrospectedColumn> addIntroCols, File targetFile, GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setExpandEntityReferences(false);
            DocumentBuilder builder = factory.newDocumentBuilder();

            builder.setEntityResolver(new NullEntityResolver());
            Document existingDocument = builder.parse(targetFile);
            Element rootNode = existingDocument.getDocumentElement();

            AmanDomWriter dw = new AmanDomWriter();
            dw.initElementList(rootNode);
            List<Element> el = dw.getElementList();
            AmanSaxWriter asw = new AmanSaxWriter();
            asw.parse(targetFile, el);

            NodeList nodeList = rootNode.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node childNode = nodeList.item(i);

                if (childNode.getNodeType() != Node.ELEMENT_NODE) {
                    continue;
                }

                if ("resultMap".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if("BaseResultMap".equals(id)){
                        List<String> hasCol = queryExistsBaseResultMap(e);
                        for(IntrospectedColumn add : addIntroCols) {
                            if(!hasCol.contains(add.getActualColumnName())){
                                Element resultElement = xmlResult(existingDocument, add);
                                appendNode(existingDocument, e, resultElement, 1);
                            }
                        }
                    }else if("ResultMapWithBLOBs".equals(id)){//不修改

                    }
                } else if ("sql".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("Base_Column_List".equals(id)) {
                        if(!containElement(e)){
                            List<String> hasCol = queryExistsBaseColumnList(e);
                            String addStr = "";
                            for (IntrospectedColumn add : addIntroCols) {
                                if(!hasCol.contains(add.getActualColumnName())){
                                    addStr += ", " + add.getActualColumnName();
                                }
                            }

                            if(addStr.length() > 0){
                                String content = e.getTextContent();
                                int insertIndex = content.replaceAll("\\s+$", "").length();
                                content = new StringBuilder(content).insert(insertIndex, addStr).toString();
                                e.setTextContent(content);
                            }
                        }
                    }else if("Blob_Column_List".equals(id)){//不修改

                    }
                } else if ("select".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("selectByPrimaryKey".equals(id)) {//不修改
                    }else if("queryByMap".equals(id)){
                    }else if("queryByEntity".equals(id)){
                    }else if("queryByPager".equals(id)){
                    }

                } else if ("delete".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("deleteByPrimaryKey".equals(id)) {//不修改
                    }
                } else if ("insert".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("insert".equals(id)) {//不修改
                        if(!containElement(e)){
                            List<String> hasCol = qeuryExistsInsert(e);

                            String addColStr = "";
                            String addValStr = "";
                            for (IntrospectedColumn add : addIntroCols) {
                                if(!hasCol.contains(add.getActualColumnName())){
                                    addColStr += ", " + add.getActualColumnName();
                                    addValStr += ", #{" + add.getJavaProperty()+",jdbcType="+add.getJdbcTypeName()+"}";
                                }
                            }

                            if(addColStr.length() > 0){
                                String content = e.getTextContent();
                                String temp = e.getTextContent().toLowerCase();
                                int colIndex = temp.substring(0, temp.indexOf(")")).replaceAll("\\s+$", "").length();
                                int valIndex = temp.replaceAll("\\s*\\)\\s*$", "").length();
                                content = new StringBuilder(content).insert(valIndex, addValStr).insert(colIndex, addColStr).toString();
                                e.setTextContent(content);
                            }
                        }
                    } else if("insertSelective".equals(id)){
                        List<String> hasCol = new ArrayList<String>();
                        Element trims0 = (Element) e.getElementsByTagName("trim").item(0);
                        Element trims1 = (Element) e.getElementsByTagName("trim").item(1);

                        String content = trims0.getTextContent();
                        String[] cols = content.replaceAll("\\s+", "").split(",");
                        for(int index =0; index < cols.length; index++){
                            hasCol.add(cols[index]);
                        }

                        for(IntrospectedColumn add : addIntroCols) {
                            if(!hasCol.contains(add.getActualColumnName())){
                                Element ifTag = existingDocument.createElement("if");
                                ifTag.setAttribute("test", add.getJavaProperty() +" != null");
                                ifTag.setTextContent(newLine + genIndent(4) + add.getActualColumnName() + "," + newLine
                                        + genIndent(3));
                                appendNode(existingDocument, trims0, ifTag, 2);

                                Element ifTag1 = existingDocument.createElement("if");
                                ifTag1.setAttribute("test", add.getJavaProperty() +" != null");
                                ifTag1.setTextContent(newLine + genIndent(4) + "#{" + add.getJavaProperty()
                                        + ",jdbcType=" + add.getJdbcTypeName() + "}," + newLine + genIndent(3));
                                appendNode(existingDocument, trims1, ifTag1, 2);
                            }
                        }
                    }
                } else if ("update".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("updateByPrimaryKeySelective".equals(id)) {//不修改
                        List<String> hasCol = new ArrayList<String>();
                        Element set = (Element) e.getElementsByTagName("set").item(0);

                        String content = set.getTextContent();
                        content = content.replaceAll("\\s+", "").replaceAll("#\\{.*\\}", "").replaceAll("=.*,", ",");
                        String[] cols = content.split(",");
                        for(int index =0; index < cols.length; index++){
                            hasCol.add(cols[index]);
                        }

                        for(IntrospectedColumn add : addIntroCols) {
                            if(!hasCol.contains(add.getActualColumnName())){
                                Element ifTag = existingDocument.createElement("if");
                                ifTag.setAttribute("test", add.getJavaProperty() +" != null");
                                ifTag.setTextContent(newLine + genIndent(4) + add.getActualColumnName() + " = #{"
                                        + add.getJavaProperty() + ",jdbcType=" + add.getJdbcTypeName() + "}," + newLine
                                        + genIndent(3));
                                appendNode(existingDocument, set, ifTag, 2);
                            }
                        }
                    }else if("updateByPrimaryKeyWithBLOBs".equals(id)){
                        if(!containElement(e)){
                            List<String> hasCol = queryExistsUpdateByPrimaryKey(e);
                            String addStr = "";
                            for (IntrospectedColumn add : addIntroCols) {
                                if (!hasCol.contains(add.getActualColumnName())) {
                                    addStr += "," + newLine + genIndent(3) + add.getActualColumnName() + " = #{"
                                            + add.getJavaProperty() + ",jdbcType=" + add.getJdbcTypeName() + "}";
                                }
                            }
                            if (addStr.length() > 0) {
                                StringTokenizer st = new StringTokenizer(e.getTextContent(), " \r\n\t", true);
                                int index = 0;
                                while (st.hasMoreTokens()) {
                                    String t = st.nextToken();
                                    if ("where".equalsIgnoreCase(t)) {
                                        break;
                                    }
                                    index += t.length();
                                }
                                String content = e.getTextContent();
                                int insertIndex = content.substring(0, index).replaceAll("\\s+$", "").length();
                                content = new StringBuilder(content).insert(insertIndex, addStr).toString();
                                e.setTextContent(content);
                            }
                        }
                    }else if("updateByPrimaryKey".equals(id)){
                        if(!containElement(e)){
                            List<String> hasCol = queryExistsUpdateByPrimaryKey(e);
                            String addStr = "";
                            for (IntrospectedColumn add : addIntroCols) {
                                if (!hasCol.contains(add.getActualColumnName())) {
                                    addStr += "," + newLine + genIndent(3) + add.getActualColumnName() + " = #{"
                                            + add.getJavaProperty() + ",jdbcType=" + add.getJdbcTypeName() + "}";
                                }
                            }
                            if (addStr.length() > 0) {
                                StringTokenizer st = new StringTokenizer(e.getTextContent(), " \r\n\t", true);
                                int index = 0;
                                while (st.hasMoreTokens()) {
                                    String t = st.nextToken();
                                    if ("where".equalsIgnoreCase(t)) {
                                        break;
                                    }
                                    index += t.length();
                                }
                                String content = e.getTextContent();
                                int insertIndex = content.substring(0, index).replaceAll("\\s+$", "").length();
                                content = new StringBuilder(content).insert(insertIndex, addStr).toString();
                                e.setTextContent(content);
                            }
                        }
                    }
                }
            }

            String source = dw.toString(existingDocument);
            BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
            bw.write(source);
            bw.close();
        } catch (Exception e) {

        }
    }

    public static boolean containElement(Element e){
        NodeList children = e.getChildNodes();
        for (int index = 0; index < children.getLength(); index++) {
            Node ei = children.item(index);
            if (ei.getNodeType() == Node.ELEMENT_NODE) {
                return true;
            }
        }
        return false;
    }

    public static void appendNode(Document d, Element e, Node n, int level){
        e.appendChild(d.createTextNode(indent));//node缩进
        e.appendChild(n);//写内容
        e.appendChild(d.createTextNode(newLine));//换行
        e.appendChild(d.createTextNode(genIndent(level)));
    }

    public static String genIndent(int level){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < level; i++) {// element缩进
            sb.append(indent);
        }
        return sb.toString();
    }

    public static List<String> queryExistsBaseResultMap(Element e) {
        List<String> hasCol = new ArrayList<String>();
        NodeList children = e.getChildNodes();
        for (int index = 0; index < children.getLength(); index++) {
            Node ei = children.item(index);
            if (ei.getNodeType() == Node.ELEMENT_NODE) {
                hasCol.add(((Element) ei).getAttribute("column"));
            }
        }
        return hasCol;
    }

    public static List<String> queryExistsBaseColumnList(Element e) {
        List<String> hasCol = new ArrayList<String>();
        String content = e.getTextContent();
        String temp = content.replaceAll("\\s+", " ");
        String[] cols = temp.split(",");

        for(int index =0; index < cols.length; index++) {
            String col = cols[index].trim();
            hasCol.add(col.split(" ")[0]);//考虑别名情况
        }
        return hasCol;
    }

    private static List<String> qeuryExistsInsert(Element e) {
        List<String> hasCol = new ArrayList<String>();
        StringTokenizer st = new StringTokenizer(e.getTextContent(), " \r\n\t(,)", true);
        boolean start = false;
        while (st.hasMoreTokens()) {
            String t = st.nextToken();
            if (" \r\n\t,".contains(t)) {
                continue;
            }
            if ("(".equals(t)) {
                start = true;
                continue;
            }
            if (")".equals(t)) {
                break;
            }
            if (start) {// value前的属性
                hasCol.add(t);
            }
        }
        return hasCol;
    }

    private static List<String> queryExistsUpdateByPrimaryKey(Element e) {
        List<String> hasCol = new ArrayList<String>();

        StringTokenizer st = new StringTokenizer(e.getTextContent(), " \r\n\t", true);
        StringBuilder sb = new StringBuilder();
        while (st.hasMoreTokens()) {
            String t = st.nextToken();
            if ("where".equalsIgnoreCase(t)) {
                break;
            }
            sb.append(t);
            if ("set".equalsIgnoreCase(t)) {
                sb.setLength(0);
            }
        }
        String content = sb.append(",").toString();
        content = content.replaceAll("\\s+", "").replaceAll("#\\{.*\\}", "").replaceAll("=.*,", ",");
        String[] cols = content.split(",");
        for(int index =0; index < cols.length; index++){
            hasCol.add(cols[index]);
        }

        return hasCol;
    }

    public static Element xmlResult(Document d, IntrospectedColumn add){
        Element e = d.createElement("result");
        e.setAttribute("column", add.getActualColumnName());
        e.setAttribute("property", add.getJavaProperty());
        e.setAttribute("jdbcType", add.getJdbcTypeName());
        return e;
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月19日 下午3:32:32
     * @param needDelFields
     * @param targetFile
     * @param sqlMap
     * @param introspectedTable
     */
    public static void mergedDelColSource(List<IntrospectedColumn> needDelFields, File targetFile,
                                          GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setExpandEntityReferences(false);
            DocumentBuilder builder = factory.newDocumentBuilder();

            builder.setEntityResolver(new NullEntityResolver());
            Document existingDocument = builder.parse(targetFile);
            Element rootNode = existingDocument.getDocumentElement();

            AmanDomWriter dw = new AmanDomWriter();
            dw.initElementList(rootNode);
            List<Element> el = dw.getElementList();
            AmanSaxWriter asw = new AmanSaxWriter();
            asw.parse(targetFile, el);

            List<String> removeList = new ArrayList<String>();
            for(IntrospectedColumn intro : needDelFields){
                removeList.add(intro.getActualColumnName());
            }

            NodeList nodeList = rootNode.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node childNode = nodeList.item(i);

                if (childNode.getNodeType() != Node.ELEMENT_NODE) {
                    continue;
                }

                if ("resultMap".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if("BaseResultMap".equals(id)){
                        List<Element> results = queryChildrenElement(e);
                        for(int index=0;index<results.size();index++){
                            Element result = results.get(index);
                            if(removeList.contains(result.getAttribute("column"))){
                                Node preNode = result.getPreviousSibling();
                                if(preNode != null && preNode.getNodeType() == Node.TEXT_NODE){
                                    String t = preNode.getTextContent();
                                    if("".equals(t.replaceAll("\\s+", ""))){
                                        e.removeChild(preNode);
                                    }
                                }
                                e.removeChild(result);
                            }
                        }
                    }else if("ResultMapWithBLOBs".equals(id)){//不修改

                    }
                } else if ("sql".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("Base_Column_List".equals(id)) {
                        if(!containElement(e)) {
                            StringBuilder sb = new StringBuilder();
                            StringTokenizer st = new StringTokenizer(e.getTextContent(), ",", true);
                            while (st.hasMoreTokens()) {
                                String t = st.nextToken();
                                if (",".equals(t)) {
                                    continue;
                                }
                                String matchCol = t.trim();
                                String colName = matchCol.replaceAll("\\s+", " ").split(" ")[0];
                                if (removeList.contains(colName)) {
                                    if(t.contains("\n")) {
                                        sb.append(t.replaceAll("[^\\s]+", ""));
                                    }
                                } else {
                                    if(StringUtils.isNotBlank(sb.toString())){
                                        sb.append(",");
                                    }
                                    sb.append(t);
                                }
                            }
                            e.setTextContent(sb.toString());
                        }
                    }else if("Blob_Column_List".equals(id)){//不修改

                    }
                } else if ("select".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("selectByPrimaryKey".equals(id)) {//不修改
                    }else if("queryByMap".equals(id)){
                    }else if("queryByEntity".equals(id)){
                    }else if("queryByPager".equals(id)){
                    }

                } else if ("delete".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("deleteByPrimaryKey".equals(id)) {//不修改
                    }
                } else if ("insert".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("insert".equals(id)) {// 不修改
                        if (!containElement(e)) {
                            String content = e.getTextContent();

                            int valuesIndex = indexOfIgnoreCase(content, "values", " \r\n\t()");
                            String insertStr = content.substring(0, valuesIndex);
                            String valuesStr = content.substring(valuesIndex);

                            String insertCol = insertStr.substring(insertStr.indexOf("(") + 1, insertStr.indexOf(")"));
                            String valuesCol = valuesStr.substring(valuesStr.indexOf("(") + 1,
                                    valuesStr.lastIndexOf(")"));
                            String temp = replace(valuesCol, ',', '@', '{', '}');
                            temp = replace(temp, ',', '@', '(', ')');
                            temp = replace(temp, ',', '@', '\'', '\'');

                            String[] vals = temp.split(",");
                            String[] cols = insertCol.split(",");

                            if (vals.length == cols.length) {
                                StringBuilder sbCol = new StringBuilder();
                                StringBuilder sbVal = new StringBuilder();
                                boolean del = true;
                                int valIndex = 0;
                                for (int index = 0; index < cols.length; index++) {
                                    String col = cols[index];
                                    String colName = col.trim();

                                    String tempVal = vals[index];
                                    String val = valuesCol.substring(valIndex, valIndex + tempVal.length());
                                    String valTrim = val.trim();
                                    valIndex += tempVal.length() + 1;//加上,

                                    if (removeList.contains(colName)) {
                                        del = true;
                                        if (col.contains("\n")) {
                                            sbCol.append(col.replace(colName, ""));
                                        }
                                        if (val.contains("\n")) {
                                            sbVal.append(val.replace(valTrim, ""));
                                        }
                                    } else {
                                        if(!del){
                                            sbCol.append(",");
                                            sbVal.append(",");
                                        }
                                        del = false;
                                        sbCol.append(col);
                                        sbVal.append(val);
                                    }
                                }

                                int cIndex = insertStr.indexOf("(") + 1;
                                int vIndex = valuesStr.indexOf("(") + 1;
                                StringBuilder newInsert = new StringBuilder(insertStr).replace(cIndex, cIndex
                                        + insertCol.length(), sbCol.toString());
                                StringBuilder newValues = new StringBuilder(valuesStr).replace(vIndex, vIndex
                                        + valuesCol.length(), sbVal.toString());
                                e.setTextContent(newInsert.append(newValues).toString());
                            }
                        }
                    } else if("insertSelective".equals(id)){
                        Element trims0 = (Element) e.getElementsByTagName("trim").item(0);
                        Element trims1 = (Element) e.getElementsByTagName("trim").item(1);
                        List<Element> ifs0 = queryChildrenElement(trims0);
                        List<Element> ifs1 = queryChildrenElement(trims1);
                        if(ifs0.size() == ifs1.size()){
                            for(int index=0;index<ifs0.size();index++){
                                Element if0 = ifs0.get(index);
                                Element if1 = ifs1.get(index);
                                String colName = if0.getTextContent().replace(",", "").replaceAll("\\s+", "");
                                if(removeList.contains(colName)){
                                    Node preNode0 = if0.getPreviousSibling();
                                    if(preNode0 != null && preNode0.getNodeType() == Node.TEXT_NODE){
                                        String t = preNode0.getTextContent();
                                        if("".equals(t.replaceAll("\\s+", ""))){
                                            trims0.removeChild(preNode0);
                                        }
                                    }
                                    trims0.removeChild(if0);

                                    Node preNode1 = if1.getPreviousSibling();
                                    if(preNode1 != null && preNode1.getNodeType() == Node.TEXT_NODE){
                                        String t = preNode1.getTextContent();
                                        if("".equals(t.replaceAll("\\s+", ""))){
                                            trims1.removeChild(preNode1);
                                        }
                                    }
                                    trims1.removeChild(if1);
                                }
                            }
                        }
                    }
                } else if ("update".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("updateByPrimaryKeySelective".equals(id)) {//不修改
                        Element set = (Element) e.getElementsByTagName("set").item(0);
                        List<Element> ifs = queryChildrenElement(set);

                        for(int index=0;index < ifs.size();index++){
                            Element ei = ifs.get(index);
                            String colName = ei.getTextContent().replaceAll("\\s+", "").replaceAll("=.*,", "");
                            if(removeList.contains(colName)){
                                Node preNode = ei.getPreviousSibling();
                                if(preNode != null && preNode.getNodeType() == Node.TEXT_NODE){
                                    String t = preNode.getTextContent();
                                    if("".equals(t.replaceAll("\\s+", ""))){
                                        set.removeChild(preNode);
                                    }
                                }
                                set.removeChild(ei);
                            }
                        }
                    }else if("updateByPrimaryKeyWithBLOBs".equals(id) || "updateByPrimaryKey".equals(id)){
                        if (!containElement(e)) {
                            String content = e.getTextContent();
                            int setIndex = indexOfIgnoreCase(content, "set", " \r\n\t");
                            int whereIndex = indexOfIgnoreCase(content, "where", " \r\n\t");
                            String cols = content.substring(setIndex + 3, whereIndex);
                            String temp = replace(cols, ',', '@', '{', '}');
                            temp = replace(temp, ',', '@', '(', ')');
                            temp = replace(temp, ',', '@', '\'', '\'');
                            String[] tempCols = temp.split(",");

                            StringBuilder sb = new StringBuilder();

                            boolean del = true;
                            int valIndex = 0;
                            for (int index = 0; index < tempCols.length; index++) {
                                String tempVal = tempCols[index];
                                String val = cols.substring(valIndex, valIndex + tempVal.length());
                                valIndex += tempVal.length() + 1;
                                String valTrim = val.trim();

                                String colName = valTrim.split("=")[0].trim();
                                if (removeList.contains(colName)) {
                                    del = true;
                                    if (val.contains("\n")) {
                                        sb.append(val.replace(valTrim, ""));
                                    }
                                } else {
                                    if(!del){
                                        sb.append(",");
                                    }
                                    del = false;
                                    sb.append(val);
                                }
                            }

                            String newStr = sb.toString().replaceAll("\n\\s*\n", "\n");//去掉空行

                            int rIndex = setIndex+3;
                            StringBuilder newValues = new StringBuilder(content).replace(rIndex,
                                    rIndex + cols.length(), newStr);
                            e.setTextContent(newValues.toString());

                        }
                    }
                }
            }

            String source = dw.toString(existingDocument);
            BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
            bw.write(source);
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static int indexOfIgnoreCase(String content, String key, String speator){
        if(speator == null || "".equals(speator)){
            speator = " \r\n\t";
        }
        StringTokenizer st = new StringTokenizer(content, speator, true);
        int index = 0;
        boolean find = false;
        while (st.hasMoreTokens()) {
            String t = st.nextToken();
            if (t.equalsIgnoreCase(key)) {
                find = true;
                break;
            }
            index += t.length();
        }
        if(!find){
            return -1;
        }
        return index;
    }

    public static String replace(String content, char replace, char replaceTo, char open, char close){
        StringBuilder sb = new StringBuilder();
        int level = 0;
        for(int i=0;i<content.length();i++){
            char c = content.charAt(i);
            if(open == close){
                if(open == c){
                    level = (level == 1) ? 0 : 1;
                }
            }else{
                if(open == c){
                    level++;
                }
                if(close == c){
                    level--;
                }
            }

            if(level != 0 && c == replace){
                c = replaceTo;
            }
            sb.append(c);
        }
        return sb.toString();
    }

    public static List<Element> queryChildrenElement(Element e){
        List<Element> list = new ArrayList<Element>();
        NodeList children = e.getChildNodes();
        for (int index = 0; index < children.getLength(); index++) {
            Node ei = children.item(index);
            if (ei.getNodeType() == Node.ELEMENT_NODE) {
                list.add((Element) ei);
            }
        }
        return list;
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月20日 上午9:17:05
     * @param updMap
     * @param targetFile
     * @param sqlMap
     * @param introspectedTable
     */
    public static void mergedUpdColSource(Map<String, IntrospectedColumn> updMap, File targetFile,
                                          GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setExpandEntityReferences(false);
            DocumentBuilder builder = factory.newDocumentBuilder();

            builder.setEntityResolver(new NullEntityResolver());
            Document existingDocument = builder.parse(targetFile);
            Element rootNode = existingDocument.getDocumentElement();

            AmanDomWriter dw = new AmanDomWriter();
            dw.initElementList(rootNode);
            List<Element> el = dw.getElementList();
            AmanSaxWriter asw = new AmanSaxWriter();
            asw.parse(targetFile, el);

            NodeList nodeList = rootNode.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node childNode = nodeList.item(i);

                if (childNode.getNodeType() != Node.ELEMENT_NODE) {
                    continue;
                }

                if ("resultMap".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if("BaseResultMap".equals(id)){
                        NodeList children = e.getChildNodes();
                        for(int index=0;index < children.getLength();index++){
                            Node child = children.item(index);
                            if(child.getNodeType() == Node.ELEMENT_NODE){
                                Element ei = (Element) child;
                                String colName = ei.getAttribute("column");
                                if(updMap.containsKey(colName)){
                                    IntrospectedColumn upd = updMap.get(colName);
                                    ei.setAttribute("column", upd.getActualColumnName());
                                    ei.setAttribute("property", upd.getJavaProperty());
                                    ei.setAttribute("jdbcType", upd.getJdbcTypeName());
                                }
                            }
                        }
                    }else if("ResultMapWithBLOBs".equals(id)){//不修改

                    }
                } else if ("sql".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("Base_Column_List".equals(id)) {
                        if(!containElement(e)) {
                            StringBuilder sb = new StringBuilder();
                            StringTokenizer st = new StringTokenizer(e.getTextContent(), ",", true);
                            while (st.hasMoreTokens()) {
                                String t = st.nextToken();
                                if (!",".equals(t)) {
                                    String matchCol = t.trim();
                                    String colName = matchCol.replaceAll("\\s+", " ").split(" ")[0];
                                    if(updMap.containsKey(colName)){
                                        int index = t.indexOf(matchCol);
                                        IntrospectedColumn upd = updMap.get(colName);
                                        t = new StringBuilder(t).replace(index, index + matchCol.length(), upd.getActualColumnName()).toString();
                                    }
                                }
                                sb.append(t);
                            }
                            e.setTextContent(sb.toString());
                        }
                    }else if("Blob_Column_List".equals(id)){//不修改

                    }
                } else if ("select".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("selectByPrimaryKey".equals(id)) {//不修改
                    }else if("queryByMap".equals(id)){
                    }else if("queryByEntity".equals(id)){
                    }else if("queryByPager".equals(id)){
                    }

                } else if ("delete".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("deleteByPrimaryKey".equals(id)) {//不修改
                    }
                } else if ("insert".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("insert".equals(id)) {// 不修改
                        if (!containElement(e)) {
                            String content = e.getTextContent();

                            int valuesIndex = indexOfIgnoreCase(content, "values", " \r\n\t()");
                            String insertStr = content.substring(0, valuesIndex);
                            String valuesStr = content.substring(valuesIndex);

                            String insertCol = insertStr.substring(insertStr.indexOf("(") + 1, insertStr.indexOf(")"));
                            String valuesCol = valuesStr.substring(valuesStr.indexOf("(") + 1,
                                    valuesStr.lastIndexOf(")"));
                            String temp = replace(valuesCol, ',', '@', '{', '}');
                            temp = replace(temp, ',', '@', '(', ')');
                            temp = replace(temp, ',', '@', '\'', '\'');

                            String[] vals = temp.split(",");
                            String[] cols = insertCol.split(",");

                            if (vals.length == cols.length) {
                                StringBuilder sbCol = new StringBuilder();
                                StringBuilder sbVal = new StringBuilder();
                                int valIndex = 0;
                                for (int index = 0; index < cols.length; index++) {
                                    String col = cols[index];
                                    String colName = col.trim();

                                    String tempVal = vals[index];
                                    String val = valuesCol.substring(valIndex, valIndex + tempVal.length());
                                    String valTrim = val.trim();
                                    valIndex += tempVal.length() + 1;//加上,

                                    if (updMap.containsKey(colName)) {
                                        IntrospectedColumn upd = updMap.get(colName);

                                        int cIndex = col.indexOf(colName);
                                        String tc = new StringBuilder(col).replace(cIndex, cIndex + colName.length(), upd.getActualColumnName()).toString();
                                        sbCol.append(tc);

                                        if ((valTrim.startsWith("#{") || valTrim.startsWith("${")) && valTrim.endsWith("}")) {
                                            String newVal = upd.getJavaProperty()+",jdbcType="+upd.getJdbcTypeName();
                                            int vIndex = val.indexOf(valTrim)+2;
                                            int vlen = valTrim.length()-3;
                                            String tv = new StringBuilder(val).replace(vIndex, vIndex + vlen, newVal).toString();
                                            sbVal.append(tv);
                                        }else{
                                            sbVal.append(val);
                                        }
                                    } else {
                                        sbCol.append(col);
                                        sbVal.append(val);
                                    }

                                    if (index < cols.length - 1) {// 不是末尾
                                        sbCol.append(",");
                                        sbVal.append(",");
                                    }
                                }

                                int cIndex = insertStr.indexOf("(") + 1;
                                int vIndex = valuesStr.indexOf("(") + 1;
                                StringBuilder newInsert = new StringBuilder(insertStr).replace(cIndex, cIndex
                                        + insertCol.length(), sbCol.toString());
                                StringBuilder newValues = new StringBuilder(valuesStr).replace(vIndex, vIndex
                                        + valuesCol.length(), sbVal.toString());
                                e.setTextContent(newInsert.append(newValues).toString());
                            }
                        }
                    } else if("insertSelective".equals(id)){
                        Element trims0 = (Element) e.getElementsByTagName("trim").item(0);
                        Element trims1 = (Element) e.getElementsByTagName("trim").item(1);
                        List<Element> ifs0 = queryChildrenElement(trims0);
                        List<Element> ifs1 = queryChildrenElement(trims1);
                        if(ifs0.size() == ifs1.size()){
                            for(int index=0;index<ifs0.size();index++){
                                Element if0 = ifs0.get(index);
                                Element if1 = ifs1.get(index);
                                String colName = if0.getTextContent().replace(",", "").replaceAll("\\s+", "");
                                if(updMap.containsKey(colName)){
                                    IntrospectedColumn upd = updMap.get(colName);

                                    if0.setAttribute("test", upd.getJavaProperty() +" != null");
                                    if0.setTextContent(newLine + genIndent(4) + upd.getActualColumnName() + "," + newLine
                                            + genIndent(3));

                                    if1.setAttribute("test", upd.getJavaProperty() +" != null");
                                    if1.setTextContent(newLine + genIndent(4) + "#{" + upd.getJavaProperty()
                                            + ",jdbcType=" + upd.getJdbcTypeName() + "}," + newLine + genIndent(3));
                                }
                            }
                        }
                    }
                } else if ("update".equals(childNode.getNodeName())) {
                    Element e = (Element) childNode;
                    String id = e.getAttribute("id");
                    if ("updateByPrimaryKeySelective".equals(id)) {//不修改
                        Element set = (Element) e.getElementsByTagName("set").item(0);
                        List<Element> ifs = queryChildrenElement(set);

                        for(int index=0;index < ifs.size();index++){
                            Element ei = ifs.get(index);
                            String colName = ei.getTextContent().replaceAll("\\s+", "").replaceAll("=.*,", "");
                            if(updMap.containsKey(colName)){
                                IntrospectedColumn upd = updMap.get(colName);
                                ei.setAttribute("test", upd.getJavaProperty() +" != null");
                                ei.setTextContent(newLine + genIndent(4) + upd.getActualColumnName() + " = #{"
                                        + upd.getJavaProperty() + ",jdbcType=" + upd.getJdbcTypeName() + "}," + newLine
                                        + genIndent(3));
                            }
                        }
                    }else if("updateByPrimaryKeyWithBLOBs".equals(id) || "updateByPrimaryKey".equals(id)){
                        if (!containElement(e)) {
                            String content = e.getTextContent();
                            int setIndex = indexOfIgnoreCase(content, "set", " \r\n\t");
                            int whereIndex = indexOfIgnoreCase(content, "where", " \r\n\t");
                            String cols = content.substring(setIndex + 3, whereIndex);
                            String temp = replace(cols, ',', '@', '{', '}');
                            temp = replace(temp, ',', '@', '(', ')');
                            temp = replace(temp, ',', '@', '\'', '\'');
                            String[] tempCols = temp.split(",");

                            StringBuilder sb = new StringBuilder();

                            int valIndex = 0;
                            for (int index = 0; index < tempCols.length; index++) {
                                String tempVal = tempCols[index];
                                String val = cols.substring(valIndex, valIndex + tempVal.length());
                                valIndex += tempVal.length() + 1;
                                String valTrim = val.trim();

                                String colName = valTrim.split("=")[0].trim();
                                if (updMap.containsKey(colName)) {
                                    IntrospectedColumn upd = updMap.get(colName);

                                    String newVal = upd.getActualColumnName() + " = #{" + upd.getJavaProperty()
                                            + ",jdbcType=" + upd.getJdbcTypeName() + "}";

                                    sb.append(val.replace(valTrim, newVal));
                                } else {
                                    sb.append(val);
                                }

                                if (index < tempCols.length - 1) {// 不是末尾
                                    sb.append(",");
                                }
                            }

                            int cIndex = setIndex + 3;
                            StringBuilder newValues = new StringBuilder(content).replace(cIndex,
                                    cols.length() + cIndex, sb.toString());
                            e.setTextContent(newValues.toString());

                        }
                    }
                }
            }

            String source = dw.toString(existingDocument);
            BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
            bw.write(source);
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月20日 上午10:23:01
     * @param targetFile
     * @param sqlMap
     * @param introspectedTable
     */
    public static void
    mergedColSource(File targetFile, GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
//        try {
//            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//            factory.setExpandEntityReferences(false);
//            DocumentBuilder builder = factory.newDocumentBuilder();
//           
//            builder.setEntityResolver(new NullEntityResolver());
//            Document existingDocument = builder.parse(targetFile);
//            Element rootNode = existingDocument.getDocumentElement();
//            
//            AmanDomWriter dw = new AmanDomWriter();
//            dw.initElementList(rootNode);
//            List<Element> el = dw.getElementList();
//            AmanSaxWriter asw = new AmanSaxWriter();
//            asw.parse(targetFile, el);
//            
//            List<IntrospectedColumn> allDbCol = introspectedTable.getAllColumns();
//            
//            NodeList nodeList = rootNode.getChildNodes();
//            for (int i = 0; i < nodeList.getLength(); i++) {
//                Node childNode = nodeList.item(i);
//
//                if (childNode.getNodeType() != Node.ELEMENT_NODE) {
//                    continue;
//                }
//
//                if ("resultMap".equals(childNode.getNodeName())) {
//                    Element e = (Element) childNode;
//                    String id = e.getAttribute("id");
//                    if("BaseResultMap".equals(id)){
//                        NodeList children = e.getChildNodes();
//                        Node preNode = null;
//                        
//                        
//                        for(int index=0;index < children.getLength();index++){
//                            if(index-1>=0){
//                                preNode = children.item(index-1);
//                            }
//                            Node child = children.item(index);
//                            if(child.getNodeType() == Node.ELEMENT_NODE){
//                                
//                                Element ei = (Element) child;
//                                
//                                if(removeList.contains(ei.getAttribute("column"))){
//                                    e.removeChild(child);
//                                    if(preNode != null && preNode.getNodeType() == Node.TEXT_NODE){
//                                        String t = preNode.getTextContent();
//                                        if("".equals(t.replaceAll("\\s+", ""))){
//                                            e.removeChild(preNode);
//                                        }
//                                    }
//                                }
//                            }
//                        }
//                    }else if("ResultMapWithBLOBs".equals(id)){//不修改
//                        
//                    }
//                } else if ("sql".equals(childNode.getNodeName())) {
//                    Element e = (Element) childNode;
//                    String id = e.getAttribute("id");
//                    if ("Base_Column_List".equals(id)) {
//                        if(!containElement(e)) {
//                            StringBuilder sb = new StringBuilder();
//                            StringTokenizer st = new StringTokenizer(e.getTextContent(), ",", true);
//                            boolean del = false;
//                            while (st.hasMoreTokens()) {
//                                String t = st.nextToken();
//                                if (",".equals(t)) {
//                                    if (del) {
//                                        continue;
//                                    } else {
//                                        sb.append(t);
//                                    }
//                                }
//                                
//                                String matchCol = t.trim();
//                                String colName = matchCol.replaceAll("\\s+", " ").split(" ")[0];
//                                
//                                if (removeList.contains(colName)) {
//                                    del = true;
//                                    if(t.contains("\n")) {
//                                        sb.append(t.replace(matchCol, ""));
//                                    }
//                                } else {
//                                    del = false;
//                                    sb.append(t);
//                                }
//                            }
//                            e.setTextContent(sb.toString());
//                        }
//                    }else if("Blob_Column_List".equals(id)){//不修改
//                        
//                    }
//                } else if ("select".equals(childNode.getNodeName())) {
//                    Element e = (Element) childNode;
//                    String id = e.getAttribute("id");
//                    if ("selectByPrimaryKey".equals(id)) {//不修改
//                    }else if("queryByMap".equals(id)){
//                    }else if("queryByEntity".equals(id)){
//                    }else if("queryByPager".equals(id)){
//                    }
//                     
//                } else if ("delete".equals(childNode.getNodeName())) {
//                    Element e = (Element) childNode;
//                    String id = e.getAttribute("id");
//                    if ("deleteByPrimaryKey".equals(id)) {//不修改
//                    }
//                } else if ("insert".equals(childNode.getNodeName())) {
//                    Element e = (Element) childNode;
//                    String id = e.getAttribute("id");
//                    if ("insert".equals(id)) {// 不修改
//                        if (!containElement(e)) {
//                            String content = e.getTextContent();
//
//                            int valuesIndex = indexOfIgnoreCase(content, "values", " \r\n\t()");
//                            String insertStr = content.substring(0, valuesIndex);
//                            String valuesStr = content.substring(valuesIndex);
//
//                            String insertCol = insertStr.substring(insertStr.indexOf("(") + 1, insertStr.indexOf(")"));
//                            String valuesCol = valuesStr.substring(valuesStr.indexOf("(") + 1,
//                                    valuesStr.lastIndexOf(")"));
//                            String temp = replace(valuesCol, ',', '@', '{', '}');
//                            temp = replace(temp, ',', '@', '(', ')');
//                            temp = replace(temp, ',', '@', '\'', '\'');
//
//                            String[] vals = temp.split(",");
//                            String[] cols = insertCol.split(",");
//
//                            if (vals.length == cols.length) {
//                                StringBuilder sbCol = new StringBuilder();
//                                StringBuilder sbVal = new StringBuilder();
//                                boolean del = false;
//                                int valIndex = 0;
//                                for (int index = 0; index < cols.length; index++) {
//                                    String col = cols[index];
//                                    String colName = col.trim();
//
//                                    String tempVal = vals[index];
//                                    String val = valuesCol.substring(valIndex, tempVal.length());
//                                    String valTrim = val.trim();
//                                    valIndex += tempVal.length() + 1;//加上,
//
//                                    if (removeList.contains(colName)) {
//                                        del = true;
//                                        if (col.contains("\n")) {
//                                            sbCol.append(col.replace(colName, ""));
//                                        }
//                                        if (val.contains("\n")) {
//                                            sbVal.append(val.replace(valTrim, ""));
//                                        }
//                                    } else {
//                                        del = false;
//                                        sbCol.append(col);
//                                        sbVal.append(val);
//                                    }
//
//                                    if (del) {
//                                        continue;
//                                    } else {
//                                        if (index < cols.length - 1) {// 不是末尾
//                                            sbCol.append(",");
//                                            sbVal.append(",");
//                                        }
//                                    }
//                                }
//
//                                StringBuilder newInsert = new StringBuilder(insertStr).replace(
//                                        insertStr.indexOf("(") + 1, insertCol.length() + 1, sbCol.toString());
//                                StringBuilder newValues = new StringBuilder(valuesStr).replace(
//                                        valuesStr.indexOf("(") + 1, valuesCol.length() + 1, sbVal.toString());
//                                e.setTextContent(newInsert.append(newValues).toString());
//                            }
//                        }
//                    } else if("insertSelective".equals(id)){
//                        Element trims0 = (Element) e.getElementsByTagName("trim").item(0);
//                        Element trims1 = (Element) e.getElementsByTagName("trim").item(1);
//                        List<Element> ifs0 = queryChildrenElement(trims0);
//                        List<Element> ifs1 = queryChildrenElement(trims1);
//                        if(ifs0.size() == ifs1.size()){
//                            for(int index=0;index<ifs0.size();index++){
//                                Element if0 = ifs0.get(index);
//                                Element if1 = ifs1.get(index);
//                                String colName = if0.getTextContent().replace(",", "").replaceAll("\\s+", "");
//                                if(removeList.contains(colName)){
//                                    trims0.removeChild(if0);
//                                    trims1.removeChild(if1);
//                                }
//                            }
//                        }
//                    }
//                } else if ("update".equals(childNode.getNodeName())) {
//                    Element e = (Element) childNode;
//                    String id = e.getAttribute("id");
//                    if ("updateByPrimaryKeySelective".equals(id)) {//不修改
//                        Element set = (Element) e.getElementsByTagName("set").item(0);
//                        List<Element> ifs = queryChildrenElement(set);
//                        
//                        for(int index=0;index < ifs.size();index++){
//                            Element ei = ifs.get(i);
//                            String colName = ei.getTextContent().replaceAll("\\s+", "").replaceAll("=.*,", "");
//                            if(removeList.contains(colName)){
//                                set.removeChild(ei);
//                            }
//                        }
//                    }else if("updateByPrimaryKeyWithBLOBs".equals(id) || "updateByPrimaryKey".equals(id)){
//                        if (!containElement(e)) {
//                            String content = e.getTextContent();
//                            int setIndex = indexOfIgnoreCase(content, "set", " \r\n\t");
//                            int whereIndex = indexOfIgnoreCase(content, "where", " \r\n\t");
//                            String cols = content.substring(setIndex + 3, whereIndex);
//                            String temp = replace(cols, ',', '@', '{', '}');
//                            temp = replace(temp, ',', '@', '(', ')');
//                            temp = replace(temp, ',', '@', '\'', '\'');
//                            String[] tempCols = temp.split(",");
//
//                            StringBuilder sb = new StringBuilder();
//
//                            boolean del = false;
//                            int valIndex = 0;
//                            for (int index = 0; index < tempCols.length; index++) {
//                                String tempVal = tempCols[index];
//                                valIndex += tempVal.length() + 1;
//                                String val = cols.substring(valIndex, tempVal.length());
//                                String valTrim = val.trim();
//
//                                String colName = valTrim.split("=")[0];
//                                if (removeList.contains(colName)) {
//                                    del = true;
//                                    if (val.contains("\n")) {
//                                        sb.append(val.replace(valTrim, ""));
//                                    }
//                                } else {
//                                    del = false;
//                                    sb.append(val);
//                                }
//
//                                if (del) {
//                                    continue;
//                                } else {
//                                    if (index < tempCols.length - 1) {// 不是末尾
//                                        sb.append(",");
//                                    }
//                                }
//                            }
//
//                            StringBuilder newValues = new StringBuilder(content).replace(setIndex + 3,
//                                    cols.length() + 3, sb.toString());
//                            e.setTextContent(newValues.toString());
//
//                        }
//                    }
//                }
//            }
//
//            String source = dw.toString(existingDocument);
//            BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile, false));
//            bw.write(source);
//            bw.close();
//        } catch (Exception e) {
//
//        }
    }

    public List<String> queryDbNotExistsCol(List<IntrospectedColumn> allDbCol, List<String> hasCol) {

        return null;
    }

}
